package com.qinyh.util.umdutil;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Random;
import java.util.zip.DeflaterOutputStream;

import com.qinyh.entity.Book;

public class UMDEncoder {
	private Book umd;
	private List<byte[]> zippedSeq;

	private UMDOutputStream out;

	private void init() throws Exception {
		umd.setHeader(-560292983);
		InputStream in;
		if (umd.getCoverFile() == null||!umd.getCoverFile().exists()) {
			in = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/liuyuan/umd/resources/cover.jpg");
		}else{
			in = new FileInputStream(umd.getCoverFile());
		}
		
		byte byts[] = new byte[in.available()];
		in.read(byts);
		in.close();
		umd.setCovers(byts);

		

		if (!hasText(umd.getTitle())) {
			throw new Exception("\u6807\u9898\u4e0d\u80fd\u4e3a\u7a7a");
		}

		if (!hasText(umd.getAuthor())) {
			throw new Exception("\u4f5c\u8005\u4e0d\u80fd\u4e3a\u7a7a");
		}

		if (!hasText(umd.getYear()) || (umd.getYear().length() > 4)) {
			throw new Exception("\u65e5\u671f\u975e\u6cd5");
		}

		if (!hasText(umd.getMonth()) || (umd.getMonth().length() > 2)) {
			throw new Exception("\u65e5\u671f\u975e\u6cd5");
		}

		if (!hasText(umd.getDay()) || (umd.getDay().length() > 2)) {
			throw new Exception("\u65e5\u671f\u975e\u6cd5");
		}

		if (!hasText(umd.getGender())) {
			throw new Exception("\u65e5\u671f\u975e\u6cd5");
		}

		if (!hasText(umd.getVendor())) {
			throw new Exception("\u65e5\u671f\u975e\u6cd5");
		}

		if ((umd.getChapterTitles() == null)
				|| (umd.getChapterTitles().size() <= 0)) {
			throw new Exception(
					"\u5185\u5bb9\u6570\u91cf\u4e0d\u80fd\u5c0f\u4e8e0");
		}

		if (umd.getChapterNumber() != umd.getChapterTitles().size()) {
			umd.setChapterNumber(umd.getChapterTitles().size());
		}

		if ((umd.getChapterContents() == null)
				|| (umd.getChapterContents().size() != umd.getChapterTitles()
						.size())) {
			throw new Exception(
					"\u7ae0\u8282\u6807\u9898\u6570\u91cf\u548c\u7ae0\u8282\u5185\u5bb9\u6570\u91cf\u4e0d\u7b26");
		}
		List<String> chapterContents = umd.getChapterContents();
		for (int i = 0; i < umd.getChapterNumber(); i++) {
			String str = chapterContents.get(i);
			str += "\u2029";
			chapterContents.set(i, str);
		}
	}

	private void prepare() throws Exception {

		List<String> chapterContents = umd.getChapterContents();
		int offsets[] = new int[umd.getChapterNumber()];
		StringBuffer content = new StringBuffer();

		int iTotalen = 0;
		for (int i = 0; i < umd.getChapterNumber(); i++) {
			String str = chapterContents.get(i);
			str = str.replace("\r\n", "\u2029");
			chapterContents.set(i, str);
			content.append(str);
			offsets[i] = iTotalen;
			iTotalen += str.length();
		}

		umd.setOffsets(offsets);

		umd.setContentLength(iTotalen);

		@SuppressWarnings("unused")
		int num = 0;
		if (((iTotalen * 2) % 0x8000) == 0) {
			num = (iTotalen * 2) / 0x8000;
		} else {
			num = (iTotalen * 2) / 0x8000 + 1;
		}

		byte ibContent[] = convertStringToLittleUnicodeBytes(content);
		ByteArrayInputStream in = new ByteArrayInputStream(ibContent);

		byte input[] = new byte[0x7fff];
		int c;
		while ((c = in.read(input)) > 0) {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			DeflaterOutputStream dos = new DeflaterOutputStream(bos);
			dos.write(input, 0, c);
			dos.close();

			zippedSeq.add(bos.toByteArray());

		}

		in.close();

	}

	public void encode(File file, Book umd) throws Exception {
		this.umd = umd;
		init();
		prepare();
		out = new UMDOutputStream(new FileOutputStream(file));
		Random rand = new Random();
		int random1 = -1;
		int random2 = -1;
		int randoms[] = new int[zippedSeq.size()];

		random1 = (0x401 + rand.nextInt(0x7fff)) % 0xffff;

		out.writeInt(umd.getHeader());
		out.writeByte(Book.POUND);
		out.writeShort(1);
		out.writeByte(0);
		out.writeByte(8);
		out.writeByte(1);
		out.writeShort(random1);

		out.writeByte(Book.POUND);
		out.writeShort(2);
		out.writeByte(0);
		out.writeByte(5 + umd.getTitle().length() * 2);
		out.writeChars(umd.getTitle());

		out.writeByte(Book.POUND);
		out.writeShort(3);
		out.writeByte(0);
		out.writeByte(5 + umd.getAuthor().length() * 2);
		out.writeChars(umd.getAuthor());

		if (hasText(umd.getYear())) {
			out.writeByte(Book.POUND);
			out.writeShort(4);
			out.writeByte(0);
			out.writeByte(5 + umd.getYear().length() * 2);
			out.writeChars(umd.getYear());
		}

		if (hasText(umd.getMonth())) {
			out.writeByte(Book.POUND);
			out.writeShort(5);
			out.writeByte(0);
			out.writeByte(5 + umd.getMonth().length() * 2);
			out.writeChars(umd.getMonth());
		}

		if (hasText(umd.getDay())) {
			out.writeByte(Book.POUND);
			out.writeShort(6);
			out.writeByte(0);
			out.writeByte(5 + umd.getDay().length() * 2);
			out.writeChars(umd.getDay());
		}

		if (hasText(umd.getGender())) {
			out.writeByte(Book.POUND);
			out.writeShort(7);
			out.writeByte(0);
			out.writeByte(5 + umd.getGender().length() * 2);
			out.writeChars(umd.getGender());
		}

		if (hasText(umd.getPublisher())) {
			out.writeByte(Book.POUND);
			out.writeShort(8);
			out.writeByte(0);
			out.writeByte(5 + umd.getPublisher().length() * 2);
			out.writeChars(umd.getPublisher());
		}

		if (hasText(umd.getVendor())) {
			out.writeByte(Book.POUND);
			out.writeShort(9);
			out.writeByte(0);
			out.writeByte(5 + umd.getVendor().length() * 2);
			out.writeChars(umd.getVendor());
		}

		out.writeByte(Book.POUND);
		out.writeShort(11);
		out.writeByte(0);
		out.writeByte(9);
		out.writeInt(umd.getContentLength() * 2);

		random1 = 0x3000 + rand.nextInt(0xfff);

		out.writeByte(Book.POUND);
		out.writeShort(0x83);
		out.writeByte(1);
		out.writeByte(9);
		out.writeInt(random1);
		out.writeByte(Book.DOLLAR);
		out.writeInt(random1);
		out.writeInt(9 + umd.getChapterNumber() * 4);

		for (int i : umd.getOffsets()) {
			out.writeInt(i * 2);
		}

		random1 = 0x4000 + rand.nextInt(0xfff);

		out.writeByte(Book.POUND);
		out.writeShort(0x84);
		out.writeByte(1);
		out.writeByte(9);
		out.writeInt(random1);
		out.writeByte(Book.DOLLAR);
		out.writeInt(random1);
		int num = 0;
		for (String chapterTitle : umd.getChapterTitles()) {
			num += chapterTitle.length() * 2 + 1;
		}
		out.writeInt(num + 9);
		for (String chapterTitle : umd.getChapterTitles()) {
			out.writeByte(chapterTitle.length() * 2);
			out.writeChars(chapterTitle);
		}

		if (zippedSeq.size() > 1) {
			random1 = rand.nextInt(zippedSeq.size() - 1);
			random2 = rand.nextInt(zippedSeq.size() - 1);
		}

		for (int i = 0; i < zippedSeq.size(); i++) {
			randoms[i] = rand.nextInt(0xfffffff) * (-1);

			out.writeByte(Book.DOLLAR);
			out.writeInt(randoms[i]);

			byte bytes[] = zippedSeq.get(i);

			out.writeInt(9 + bytes.length);
			out.write(bytes, 0, bytes.length);

			if (i == random1) {
				out.writeByte(Book.POUND);
				out.writeShort(0xf1);
				out.writeByte(0);
				out.writeByte(0x15);
				out.writeBytes("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
			}

			if (i == random2) {
				out.writeByte(Book.POUND);
				out.writeShort(10);
				out.writeByte(0);
				out.writeByte(9);
				out.writeInt(umd.getContentId());
			}
		}

		random1 = 0x2000 + rand.nextInt(0xfff);

		out.writeByte(Book.POUND);
		out.writeShort(0x81);
		out.writeByte(1);
		out.writeByte(9);
		out.writeInt(random1);
		out.writeByte(Book.DOLLAR);
		out.writeInt(random1);
		out.writeInt(9 + randoms.length * 4);

		for (int random : randoms) {
			out.writeInt(random);
		}

		if ((umd.getCovers() != null) && (umd.getCovers().length > 0)) {
			random1 = 0x1000 + rand.nextInt(0xfff);

			out.writeByte(Book.POUND);
			out.writeShort(0x82);
			out.writeByte(1);
			out.writeByte(10);
			out.writeByte(1);
			out.writeInt(random1);
			out.writeByte(Book.DOLLAR);
			out.writeInt(random1);

			out.writeInt(9 + umd.getCovers().length);
			out.write(umd.getCovers(), 0, umd.getCovers().length);
		}

		out.writeByte(Book.POUND);
		out.writeShort(0x0c);
		out.writeByte(1);
		out.writeByte(9);
		out.writeInt(4 + out.size());

		out.close();
	}

	private byte[] convertStringToLittleUnicodeBytes(StringBuffer src) {
		char[] chars = src.toString().toCharArray();
		ByteBuffer buffer = ByteBuffer.allocate(chars.length * 2);
		for (char c : chars) {
			buffer.put((byte) ((c >>> 0) & 0xff));
			buffer.put((byte) ((c >>> 8) & 0xff));
		}
		return buffer.array();
	}

	private boolean hasText(String src) {
		if ((src == null) || src.equals("")) {
			return false;
		}
		return true;
	}

}
